﻿/********
* 
* 
*  Description:
*  Create By kain.hong at 7/20/2010 1:25:24 PM
*  
*
*  Revision History:
*  Date                  Who                 What
*  
* 
*/
#region namespace

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Configuration;
using System.Globalization;
using System.Reflection;

#endregion


namespace Cherry.Agile.Data.DataAccess
{
    /// <summary>
    /// 根据配置信息创建DbConnection<see cref="DbConnection"/>
    /// </summary>
    internal sealed class DbProviderFactory
    {
        public static DbConnection GetDbConnection(string connectionString)
        {
            if (string.IsNullOrEmpty(connectionString))
                throw new ArgumentNullException("connectionString");
            var keyName = connectionString.Split('=').Last().Trim();

            var section = System.Configuration.ConfigurationManager.ConnectionStrings;
            if (section == null || section.Count == 0)
                throw new ArgumentException("configruation information is empty");
            ConnectionStringSettings current = null;

            foreach (ConnectionStringSettings item in section)
            {
                if (item.Name.Equals(keyName, StringComparison.CurrentCultureIgnoreCase))
                {
                    current = item;
                    break;
                }
            }

            if (current == null)
                throw new ArgumentOutOfRangeException("invalide connection string:" + connectionString);

            if (DbProviderMapping.DefaultSqlProviderName == current.ProviderName || string.IsNullOrEmpty(current.ProviderName))
            {
                var factory = System.Data.Common.DbProviderFactories.GetFactory(DbProviderMapping.DefaultSqlProviderName);
                var con = factory.CreateConnection();
                con.ConnectionString = current.ConnectionString;
                return con;
            }
            else if (DbProviderMapping.DefaultOracleProviderName == current.ProviderName)
            {
                var factory = System.Data.Common.DbProviderFactories.GetFactory(DbProviderMapping.DefaultOracleProviderName);
                var con = factory.CreateConnection();
                con.ConnectionString = current.ConnectionString;
                return con;
            }
            else if (DbProviderMapping.DefualtEntityProviderName == current.ProviderName)
            {
                var asm = Assembly.Load("System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
                if (asm == null)
                    throw new ArgumentException("Unable to find the requested .Net Framework Data Provider.It may not be installed.");
                var type = asm.GetType("System.Data.EntityClient.EntityConnection");
                if (type == null)
                    throw new ArgumentException("Unable to find the requested .Net Framework Data Provider.It may not be installed.");

                try
                {
                    return Activator.CreateInstance(type, connectionString) as DbConnection;
                }
                catch (System.Reflection.TargetInvocationException tie)
                {
                    throw new InvalidOperationException("invalid data connect provider,make sure add valide data connection provider.", tie);
                }
                catch(System.Exception)
                {
                    throw new ArgumentOutOfRangeException("invalid data connection string,the correct connection string format is 'name={connectStringName}'");//连接字符串必须满足name={connectStringName}格式,或者是完整的连接字符串。", ex);
                }
               
            }
            else
            {
                var factory = System.Data.Common.DbProviderFactories.GetFactory(current.ProviderName);
                var con  = factory.CreateConnection();
                con.ConnectionString = current.ConnectionString;
                return con;
            }
        }
    }
}
